#pragma once

#include <iostream>
#include <queue>
#include <mutex>
#include <pthread.h>
#include "lockGuard.hpp"

const int gDefaultCap = 5;

template <class T>
class BlockQueue
{
private:
    size_t size()
    {
        return Bqueue_.size();
    }

    bool ifFull()
    {
        return size() == capacity_;
    }

    bool isEmpty()
    {
        return size() == 0;
    }

public:
    BlockQueue(size_t capacity = gDefaultCap)
        : capacity_(capacity)
    {
        pthread_mutex_init(&mtx_, nullptr);
        pthread_cond_init(&Full_, nullptr);
        pthread_cond_init(&Empty_, nullptr);
    }

    void push(const T &in) // 生产者
    {
        lockGuard lockguard(&mtx_);
        // pthread_mutex_lock(&mtx_);

        while (ifFull()) // 可能出现伪唤醒或唤醒函数调用失败
            pthread_cond_wait(&Empty_, &mtx_);

        // 走这一步，说明资源100%就绪，可以下一步操作
        Bqueue_.push(in);
        if (Bqueue_.size() >= capacity_ / 2)
            pthread_cond_signal(&Empty_);
        // pthread_mutex_unlock(&mtx_);
    }

    void pop(T *out) // 消费者
    {
        lockGuard lockguard(&mtx_);
        // pthread_mutex_lock(&mtx_);
        while (isEmpty())
            pthread_cond_wait(&Full_, &mtx_);

        *out = Bqueue_.front();
        Bqueue_.pop();
        pthread_cond_signal(&Empty_);
        // pthread_mutex_unlock(&mtx_);
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&mtx_);
        pthread_cond_destroy(&Full_);
        pthread_cond_destroy(&Empty_);
    }

private:
    std::queue<T> Bqueue_;
    size_t capacity_;
    pthread_mutex_t mtx_;
    pthread_cond_t Full_;  // 判断队列是否为满
    pthread_cond_t Empty_; // 判断队列是否为空
};
